;function XuChess () {

  if (!(this instanceof XuChess)) {
    return new XuChess();
  };

  this.$outerDom = $('.xu-chess');
  this.SIDE_LENGTH = Math.floor(this.$outerDom.width() / 8);  // 棋盘边长
  this.CHESS_SIDE = this.SIDE_LENGTH * 7 / 8;    //棋子边长

  this.chessboard = []; // 二维数组

  this.initChessboard = XuChessOptions.initChessboard;
  this.rules = XuChessOptions.rules;

  this.moving = false;

  this.init();
  this.publishEvent();

}

XuChess.prototype = {

  //  初始化
  init: function () {
    this.chessboardCache = [];  // 棋盘缓存数组

    var chesses = this.initChessboard;
    var cells = this.chessboard;
    this.count = 0;

    var firstInit = !$('.xu-chess-cell').length;

    for (var i = 0; i < 10; i ++) {
      cells[i] = [];
      for (var j = 0; j < 9; j ++) {
        cells[i][j] = null;
        if (firstInit) {
          var $el = $('<div>')
            .addClass('xu-chess-cell xu-chess-cell-' + i + '-' + j);
        } else {
          var $el = $('.xu-chess-cell-' + i + '-' + j);
        };
        
        $el.css({
          position: 'absolute',
          width: this.CHESS_SIDE + 'px',
          height: this.CHESS_SIDE + 'px',
          lineHeight: this.CHESS_SIDE + 'px',
          borderRadius: this.CHESS_SIDE / 2 + 'px',
          top: i * this.SIDE_LENGTH + 'px',
          left: j * this.SIDE_LENGTH + 'px'
        });
        this.$outerDom.append($el);

      }
    }

    for (var key in chesses) {
      var pos = key.split(' ');
      var value = chesses[key];
      cells[pos[0]][pos[1]] = {
        type: value.type,
        text: value.text,
        color: + pos[0] <= 4 ? 'black': 'red'
      };
    }
    this.render();
  },

  //  渲染页面
  render: function () {
    var cells = this.chessboard;
    var result = null;
    var that = this;
    for (var i = 0; i < cells.length; i ++) {
      for (var j = 0; j < cells[i].length; j ++) {
        var cell = cells[i][j];
        this.chearChess(i, j);
        if (cell) {
          this.resetChess(i, j, cell);
        }
      }
    }

    var result = this.isResult();

    this.nextTick(function () {
      if (result.red) {
        alert('红方失败');
        that.init();
      }
      if (result.black) {
        alert('黑方失败');
        that.init();
      }
    })
  },
  nextTick: function (cb) {
    setTimeout(function () {
      cb();
    }, 0);
  },
  //  重置象棋的dom元素
  resetChess: function (i, j, options) {
    var $el = $('.xu-chess-cell-' + i + '-' + j);
    $el.addClass('xu-chess-cell-occ xu-chess-cell-occ-' + options.color)
      .css({
        top: i * this.SIDE_LENGTH + 'px',
        left: j * this.SIDE_LENGTH + 'px'
      })
      .text(options.text)
      .attr('data-type', options.type)
      .attr('data-color', options.color);
  
  },
  //  清除象棋内容
  chearChess: function (i, j) {
    var $el = $('.xu-chess-cell-' + i + '-' + j);
    $el.removeClass()
      .addClass('xu-chess-cell xu-chess-cell-' + i + '-' + j)
      .css({
        top: i * this.SIDE_LENGTH + 'px',
        left: j * this.SIDE_LENGTH + 'px',
        zIndex: 1
      })
      .text('')
      .removeAttr('data-type')
      .removeAttr('data-color');
  },
  publishEvent: function () {
    var _this = this;
    this.$outerDom.on('click', '.xu-chess-cell', function (ev) {
      //  如果当前元素是棋子，那么有三种情况
      //  1. 有激活棋子，并且当前棋子为敌方，杀敌行为。
      //  2. 有激活棋子，并且当前棋子为友方，激活状态改变
      //  3. 无激活棋子，该棋子变为激活状态
      //  如果当前元素不是棋子，那么有两种情况
      //  1. 有激活棋子，移动行为
      //  2. 无激活棋子，不做处理

      //  红黑各走一步。
      if ($(this).hasClass('xu-chess-cell-occ') && !$('.xu-chess-cell.active').length) {
        if (_this.count % 2) {
          if ($(this).attr('data-color') == 'red') {
            return false;
          };
        } else {
          if ($(this).attr('data-color') == 'black') {
            return false;
          };
        }
      }
      //  移动中不能进行其他操作
      if (_this.moving) {
        return;
      };

      if ($(this).hasClass('xu-chess-cell-occ')) {
        if ($('.xu-chess-cell.active').length) {
          if ($('.xu-chess-cell.active').attr('data-color') != $(this).attr('data-color')) {
            _this.action($('.xu-chess-cell.active'), $(this), true);
          } else {
            $('.xu-chess-cell').removeClass('active');
            $(this).addClass('active');
            return;
          }
        } else {
          $('.xu-chess-cell').removeClass('active');
          $(this).addClass('active');
          return;
        }
      } else if ($('.xu-chess-cell.active').length) {
        _this.action($('.xu-chess-cell.active'), $(this), false);
      }

    })
  },
  //  行为方法，移动和杀敌
  action: function ($active, $target, killed) {
    var _this = this;
    var cells = this.chessboard;
    if (this.isMove($active, $target, killed)) {
      var start = this.getCoord($active);
      var end = this.getCoord($target);
      this.moveChess($active, end[0], end[1], function () {

        _this.chessboardCache.push($.extend(true, [], cells));

        var options = cells[start[0]][start[1]];
        cells[start[0]][start[1]] = null;
        cells[end[0]][end[1]] = options;
        $('.xu-chess-cell').removeClass('active');
        _this.moving = false;

        _this.render();
        _this.count++;
      })
    } else {
      $('.xu-chess-cell').removeClass('active');
    }

  },
  //  判断是否可移动的
  isMove: function ($active, $target, isKilled) {

    var cells = this.chessboard;

    var start = this.getCoord($active);
    var end = this.getCoord($target);

    var type = $active.attr('data-type');
    var rule = this.rules[type];

    if (!this.actionVaildByType(type, start, end, rule.type, rule.killType, isKilled)) {
      return false;
    };

    if (!this.actionVaildByArea(type, end, rule.limitArea, isKilled)) {
      return false;
    };

    if (!this.actionVaildByLimitStep(type, start, end, rule.limitStep, isKilled)) {
      return false;
    };

    return true;

  },
  moveChess: function ($el, toRow, toCol, fn) {
    this.moving = true;
    $el.css('z-index', 9).animate({
      top: toRow * this.SIDE_LENGTH + 'px',
      left: toCol * this.SIDE_LENGTH + 'px'
    }, 500, fn);
  },
  //  根据dom获取坐标
  getCoord: function ($el) {
    var className = $el[0].className;
    var str = className.replace(/[^\d]/g, '');
    return [+ str.slice(0,1), + str.slice(-1)];
  },
  //  判断两个坐标是否在一条线上
  inOneLine: function (start, end) {
    return !(start[0] != end[0] && start[1] != end[1]);
  },


  //  判断行走路线是否合法 
  //  判断炮的杀敌行为是否合法
  actionVaildByType: function (chessType, start, end, type, killType, killed) {
    var cells = this.chessboard;

    switch (type) {
      case 1: 
        //  直线行走
        if (! this.inOneLine(start, end)) {
          return false;
        };
        var row, col, rows = [start[0], end[0]].sort(), cols = [start[1], end[1]].sort();
        var countChess = 0;
        if (start[0] == end[0]) {
          // 在一行
          row = start[0];
          for (var j = cols[0] + 1; j < cols[1]; j ++) {
            if (cells[row][j]) {
              countChess++;
            }
          }
        } else {
          //  在一列
          col = start[1];
          for (var i = rows[0] + 1; i < rows[1]; i ++) {
            if (cells[i][col]) {
              countChess++;
            }
          }
        }

        if (killType == 1 && countChess) {
          return false;
        }
        if (killType == 2) {
          if (killed && countChess != 1) {
            return false;
          }
          if (!killed && countChess) {
            return false;
          }
        }
        break;
      case 2:
        //  日字
        if (this.inOneLine(start, end)) {
          return false;
        }
        var cutRow = start[0] - end[0],
          cutCol = start[1] - end[1],
          signRow = 1, signCol = 1;

          if (cutRow < 0) {
            cutRow = - cutRow;
            signRow = -1;
          } 
          if (cutCol < 0) {
            cutCol = -cutCol;
            signCol = -1;
          }

          if (cutRow + cutCol != 3) {
            console.log('步数错误');
            return false;
          }
          if (cutRow == 2 && cells[start[0] - signRow][start[1]] || cutCol == 2 && cells[start[0]][start[1] - signCol]) {
            //  蹩马腿
            console.log('蹩马腿');
            return false;
          }
        break;
      case 3: 
        //  田字
        if (this.inOneLine(start, end)) {
          return false;
        }

        var cutRow = start[0] - end[0],
          cutCol = start[1] - end[1],
          signRow = 1, signCol = 1;

        if (cutRow < 0) {
          cutRow = - cutRow;
          signRow = -1;
        }
        if (cutCol < 0) {
          cutCol = - cutCol;
          signCol = - 1;
        }

        if (cutRow != 2 || cutCol != 2) {
          console.log('步数错误');
          return false;
        }

        if (cells[start[0] - signRow][start[1] - signCol]) {
          console.log('别象眼');
          return false;
        }
        break;
      case 4:
        //  士

        if (this.inOneLine(start, end)) {
          return false;
        }

        var cutRow = Math.abs(start[0] - end[0]),
          cutCol = Math.abs(start[1] - end[1]);

        if (cutRow != 1 || cutCol != 1) {
          console.log('步数错误');
          return false;
        }
        break;
      case 5:
        if (!this.inOneLine(start, end)) {
          return false;
        }
        var cutRow = start[0] - end[0],
          cutCol = Math.abs(start[1] - end[1]);

        if (cutRow < 0) {
          console.log('不能后退');
          return false;
        }
        if (cutRow + cutCol != 1 || (start[0] > 4 && cutCol)) {
          console.log('步数错误');
          return false;
        }
        break;
      case 6:
        if (!this.inOneLine(start, end)) {
          return false;
        }
        var cutRow = start[0] - end[0],
          cutCol = Math.abs(start[1] - end[1]);

        if (cutRow > 0) {
          console.log('不能后退');
          return false;
        }
        if (- cutRow + cutCol != 1 || start[0] < 5 && cutCol) {
          console.log('步数错误');
          return false;
        }
        break;
    }
    return true;
  },
  //  判断活动范围是否合法
  actionVaildByArea: function (chessType, coord, area, isKilled) {
    if (!area) {
      return true;
    }
    var start = $.extend(true, [], area.start[0]);
    var end = $.extend(true, [], area.end[1]);
    //  将帅杀敌行为
    if ((chessType === '5' || chessType === '11') && isKilled) {
      if (chessType === '5') {
        end[0] = (start[0] = 7) + 2;
      } else {
        end[0] = (start[0] = 0) + 2;
      }
    }

    if (coord[0] < start[0] || coord[1] < start[1] || coord[0] > end[0] || coord[1] > end[1]) {
      console.log('超出范围');
      return false;
    }
    return true;
  },
  //  判断移动距离是否合法
  actionVaildByLimitStep: function (chessType, start, end,limitStep, isKilled) {
    if (!limitStep) {
      return true;
    }

    var cutRow = Math.abs(start[0] - end[0]);
    var cutCol = Math.abs(start[1] - end[1]);
    //  将帅杀敌行为
    if ((chessType === '5' || chessType === '11') && isKilled) {
      return true;
    }

    if (cutRow > limitStep || cutCol > limitStep) {
      return false;
    }
    return true;

  },
  //  未完成
  back: function () {

    var prevChessboard = this.chessboardCache.pop();

    if (prevChessboard && prevChessboard.length) {
      this.chessboard = prevChessboard;
      this.count--;
      this.render();
    } else {
      alert('已经是最开始了');
    }
  },

  //  判断是否结束棋局
  isResult: function () {
    var cells = this.chessboard;

    var redFail = true;
    var blackFail = true;

    for (var i = 0; i < cells.length; i ++) {
      for (var j = 0; j < cells[i].length; j ++) {
        var cell = cells[i][j];
        var type = cell && cell.type;

        switch (type) {
          case 5:
            blackFail = false;
            break;
          case 11:
            redFail = false;
            break;
          default:
            continue;
        }
      }
    }
    return {
      red: redFail,
      black: blackFail
    }
  }

}